package net.martinimix.edesk.search;

import net.martinimix.edesk.search.AbstractRecordSearch;
import net.martinimix.edesk.search.ProductSearch;
import net.martinimix.edesk.search.RecordSearch;
import net.martinimix.edesk.search.SkuSearch;

import com.bluemartini.dna.BMContext;
import com.bluemartini.dna.BMException;
import com.bluemartini.dna.BusinessObject;
import com.bluemartini.dna.BusinessObjectArray;
import com.bluemartini.dna.DNAList;
import com.bluemartini.dna.DNAStringArray;

/**
 * Provides a multiple search term based record search implementation.
 * 
 * @author Kinjal Khamar
 *
 */
public final class MultiTermRecordSearch extends AbstractRecordSearch implements RecordSearch {

	private static final String COMMA_DELIMITED_LIST_TOKEN = "{";
	private static final String SPACE_DELIMITED_LIST_TOKEN = "[";
	
	/**
	 * Creates a new muli-record search.
	 */
	public MultiTermRecordSearch() {
		super();
	}
	
	/**
	 * Returns true if the given search input represents a multi-record search.
	 */
	public boolean isMultiTermRecordSearch(final BusinessObject searchInput) {
		final String terms = searchInput.getString("searchFor", "");
		return terms.startsWith(COMMA_DELIMITED_LIST_TOKEN) || terms.startsWith(SPACE_DELIMITED_LIST_TOKEN);
	}
	
	protected DNAList searchInternal(
			final String searchTerms, 
			final int firstRow,
			final int maxRows, 
			final DNAStringArray objectTypes) throws BMException {
		
		final String[] searchTokens;
		if (objectTypes.size() > 1) {
			throw new BMException(
					"Multiple record searching only supports a single object type at a time.  " +
					"Please limit your search to only Products or SKUs.");
		}		
		searchTokens = searchTerms.split(this.delimiter(searchTerms));		
		return this.searchInternal(searchTokens, firstRow, maxRows, objectTypes);
	}
	
	protected DNAList searchInternal(
			final String[] searchTerms, 
			final int firstRow,
			final int maxRows, 
			final DNAStringArray objectTypes) throws BMException {
				
		final BusinessObjectArray searchResults = new BusinessObjectArray();
		final DNAList response = new DNAList();
		
		
		if(objectTypes.contains("PRODUCT")) {
			searchResults.addElements(createProductSearchResults(searchTerms));
		}
		
		if(objectTypes.contains("SKU")) {
			searchResults.addElements(createSkuSearchResults(searchTerms));
		}
		
		response.setInteger("totalRows", searchResults.size());
		 
		
		if(searchResults.size() > maxRows) {
			
			final BusinessObjectArray filteredResults = new BusinessObjectArray(maxRows);
			
			for(int i = firstRow; i < (firstRow + maxRows) && i < searchResults.size(); i++) {
				filteredResults.addElement(searchResults.elementAt(i));
			}
			
			response.setBusinessObjectArrayRef("OBJECT_ARRAY", filteredResults);
			
		} else {
			response.setBusinessObjectArrayRef("OBJECT_ARRAY", searchResults);
		}
		
		return response;
	}
	
    private BusinessObjectArray createSkuSearchResults(final String[] searchTerms) throws BMException {
		
		final DNAList config = BMContext.getConfig("pdc.endeca.search.dna");
		final BusinessObjectArray searchResults = new BusinessObjectArray();
		BusinessObjectArray skuResults;
		
		final SkuSearch skuSearch =
			new SkuSearch(
					config.getString("endecaHost"),
					config.getInteger("endecaPort", 5555), // default ENE port
					config.getString("skuIdProperty"));
						
		for(int i = 0; i < searchTerms.length; i++) {
			System.out.println("i: "+i);
			String searchvalue = searchTerms[i].replaceAll("[^a-zA-Z 0-9]+", "");
		    skuResults = skuSearch.findSkus(searchvalue);
		    for(int j = 0; j < skuResults.size(); j++) {
				searchResults.addElementRef(getGenericObject(skuResults.elementAt(j)));
			}

		}
		System.out.println("searchResults: "+searchResults);	
		return searchResults;
		
	}

    private BusinessObjectArray createProductSearchResults(final String[] searchTerms) throws BMException {
		
		final DNAList config = BMContext.getConfig("pdc.endeca.search.dna");
		final BusinessObjectArray searchResults = new BusinessObjectArray();
		BusinessObjectArray productResults;
		
		final ProductSearch productSearch =
			new ProductSearch(
					config.getString("endecaHost"),
					config.getInteger("endecaPort", 5555), // default ENE port
					config.getString("productIdProperty"));
		
		for(int i = 0; i < searchTerms.length; i++) {			
			String searchvalue = searchTerms[i].replaceAll("[^a-zA-Z 0-9]+", "");
			productResults = productSearch.findProducts(searchvalue);
		    for(int j = 0; j < productResults.size(); j++) {
				searchResults.addElementRef(getGenericObject(productResults.elementAt(j)));
			}

		}
		
		return searchResults;
	}

	/**
	 * Return the delimiter for the given list of search terms.
	 * @param searchTerms
	 * @return
	 */
	public String delimiter(final String searchTerms) {
		
		if (searchTerms.startsWith(COMMA_DELIMITED_LIST_TOKEN)) {
			return "," ;
		}
		
		return " ";
	}

}
